/*
 jChecs: a Java chess game sample 

 Copyright (C) 2006-2011 by David Cotton

 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
 Foundation; either version 2 of the License, or (at your option) any later
 version.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

 You should have received a copy of the GNU General Public License along with
 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
 Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */
package fr.free.jchecs.swg;

import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.swing.DefaultListCellRenderer;
import javax.swing.Icon;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import fr.free.jchecs.ai.Engine;
import fr.free.jchecs.ai.EngineFactory;
import fr.free.jchecs.core.Player;

import static fr.free.jchecs.swg.ResourceUtils.getI18NString;
import static fr.free.jchecs.swg.ResourceUtils.getImageIcon;

/**
 * Boite de dialogue permettant d'éditer les paramètres d'un joueur.
 * 
 * SILVA - Dialog box allowing to edit the parameters of a player.
 * 
 * @author David Cotton
 */
final class PlayerDialog {
	/** Liste des définitions de types de joueurs. 
	 * 
	 * 	SILVA - List of types of players
	 * */
	private static final PlayerType[] PLAYER_TYPES;
	static {
		final List<PlayerType> liste = new ArrayList<PlayerType>();
		liste.add(new PlayerType(getI18NString("label.player.human"), true));
		final String[] noms = EngineFactory.getNames();
		Arrays.sort(noms);
		for (final String n : noms) {
			liste.add(new PlayerType(n.substring(n.indexOf('.') + 1), false));
		}
		PLAYER_TYPES = liste.toArray(new PlayerType[liste.size()]);
	}

	/**
	 * Classe utilitaire : ne pas instancier.
	 * Utility class : do not instantiate
	 */
	private PlayerDialog() {
		// Rien de spécifique... ( SILVA - Nothing special... )
	}

	/**
	 * Affiche la boite de dialogue. (TRANS: Displays the dialog box)
	 * 
	 * @param pParent
	 *            Composant parent de la boite de dialogue (peut être à null).
	 * @param pJoueur
	 *            Définition du joueur à éditer.
	 */
	static void showAboutDialog(final Component pParent, final Player pJoueur) {
		assert pJoueur != null;

		final String icone;
		final String suffixCle;
		if (pJoueur.isWhite()) {
			suffixCle = ".white";
			icone = "white22.png";
		} else {
			suffixCle = ".black";
			icone = "black22.png";
		}

		final GridBagLayout gbl = new GridBagLayout();
		final GridBagConstraints gbc = new GridBagConstraints();
		final JPanel fond = new JPanel(gbl);

		final JLabel labType = new JLabel(getI18NString("dialog.players.type"));
		gbc.anchor = GridBagConstraints.WEST;
		gbc.fill = GridBagConstraints.HORIZONTAL;
		gbc.ipadx = 8;
		gbl.setConstraints(labType, gbc);
		fond.add(labType);

		final JComboBox comboTypes = new JComboBox(PLAYER_TYPES);
		comboTypes.setRenderer(new PlayerTypeRenderer());
		final String nom = pJoueur.getName();
		for (final PlayerType pt : PLAYER_TYPES) {
			if (pt.getName().equals(nom)) {
				comboTypes.setSelectedItem(pt);
				break;
			}
		}
		gbc.gridx = 1;
		gbl.setConstraints(comboTypes, gbc);
		fond.add(comboTypes);

		final JLabel labProf = new JLabel(getI18NString("dialog.players.depth"));
		gbc.gridx = 0;
		gbc.gridy = 1;
		gbl.setConstraints(labProf, gbc);
		fond.add(labProf);

		final JSlider depthSlider = new JSlider();
		depthSlider.setMajorTickSpacing(1);
		depthSlider.setPaintLabels(true);
		depthSlider.setSnapToTicks(true);
		final Engine moteur = pJoueur.getEngine();
		if (moteur == null) {
			depthSlider.setMinimum(0);
			depthSlider.setValue(0);
			depthSlider.setMaximum(0);
		} else {
			depthSlider.setMinimum(moteur.getMinimalSearchDepth());
			depthSlider.setMaximum(moteur.getMaximalSearchDepth());
			depthSlider.setValue(moteur.getSearchDepthLimit());
		}
		gbc.gridx = 1;
		gbl.setConstraints(depthSlider, gbc);
		fond.add(depthSlider);

		comboTypes.addItemListener(new ItemListener() {
			/**
			 * Réagit à la sélection dans la combo des types.
			 * 
			 * @param pEvent
			 *            Evènement signalant la sélection.
			 */
			@Override
			public void itemStateChanged(final ItemEvent pEvent) {
				assert pEvent != null;

				if (pEvent.getStateChange() == ItemEvent.SELECTED) {
					final Object item = pEvent.getItem();
					if (item instanceof PlayerType) {
						final PlayerType pt = (PlayerType) item;
						final String n = pt.getName();
						if (pt.isHuman()) {
							pJoueur.setEngine(null);
							depthSlider.setMinimum(0);
							depthSlider.setValue(0);
							depthSlider.setMaximum(0);
						} else {
							final Engine m = EngineFactory
									.newInstance("jChecs." + n);
							depthSlider.setMinimum(m.getMinimalSearchDepth());
							depthSlider.setMaximum(m.getMaximalSearchDepth());
							depthSlider.setValue(m.getSearchDepthLimit());
							pJoueur.setEngine(m);
						}
						pJoueur.setName(n);
					} else {
						assert false;
					}
				}
			}
		});

		depthSlider.addChangeListener(new ChangeListener() {
			/**
			 * Réagit aux changements de profondeur de recherche.
			 * 
			 * @param pEvent
			 *            Evènement signalant la modification.
			 */
			@Override
			public void stateChanged(final ChangeEvent pEvent) {
				assert pEvent != null;

				if (!depthSlider.getValueIsAdjusting()) {
					final Engine m = pJoueur.getEngine();
					if (m != null) {
						m.setSearchDepthLimit(depthSlider.getValue());
					}
				}
			}
		});

		final JOptionPane op = new JOptionPane(fond, JOptionPane.PLAIN_MESSAGE,
				JOptionPane.DEFAULT_OPTION, getImageIcon(icone));

		final JDialog dialog = op.createDialog(pParent,
				getI18NString("dialog.players.title" + suffixCle));
		dialog.pack();
		dialog.setResizable(false);
		dialog.setLocationRelativeTo(pParent);
		dialog.setVisible(true);
	}

	/**
	 * Description interne d'un type de joueur.
	 * TRANS: Internal description of a type of player.
	 */
	private static final class PlayerType {
		/** Nom du type du joueur. 
		 *  TRANS - Name of the type of player
		 * */
		private final String _name;

		/** Indicateur de type de joueur humain. 
		 * 	TRANS - Type of human player
		 * */
		private final boolean _human;

		/**
		 * Instancie une nouvelle desccription de type de joueur.
		 * TRANS - Instantiates a new desccription type of player.
		 * 
		 * @param pNom
		 *            Nom du type du joueur.
		 * @param pHumain
		 *            Indicateur à vrai si le type correspond à "Humain".
		 */
		PlayerType(final String pNom, final boolean pHumain) {
			assert pNom != null;

			_name = pNom;
			_human = pHumain;
		}

		/**
		 * Renvoi le nom du type de joueur.
		 * TRANS - Returns the name of type of player
		 * 
		 * @return Nom du type de joueur.
		 */
		String getName() {
			assert _name != null;
			return _name;
		}

		/**
		 * Indique si le typecorrespond à "Humain".
		 * 
		 * @return Vrai si c'est un type "Humain".
		 */
		boolean isHuman() {
			return _human;
		}
	}

	/**
	 * Afficheur d'un type de joueur.
	 * TRANS - Viewing type of player
	 * 
	 */
	private static final class PlayerTypeRenderer extends
			DefaultListCellRenderer {
		/** Icône des types "I.A.". */
		private static final Icon COMPUTER_ICON = getImageIcon("ai16.png");

		/** Icône des types "Humain". */
		private static final Icon HUMAN_ICON = getImageIcon("human16.png");

		/** Identifiant de la classe pour la sérialisation. */
		private static final long serialVersionUID = 3936682708234009054L;

		/**
		 * Créé une nouvelle instance.
		 */
		PlayerTypeRenderer() {
			// Rien de spécifique...
		}

		/**
		 * Spécialisation de l'affichage des type de joueurs.
		 * 
		 * @param pListe
		 *            Liste déroulante ciblée.
		 * @param pObjet
		 *            Objet correspondant à l'élément de la liste à afficher.
		 * @param pIndex
		 *            Indice de l'élément dans la liste.
		 * @param pSelection
		 *            A vrai si l'élément est sélectionné.
		 * @param pFocus
		 *            A vrai si l'élément a le focus.
		 * @return Composant graphique à afficher.
		 */
		@Override
		public Component getListCellRendererComponent(final JList pListe,
				final Object pObjet, final int pIndex,
				final boolean pSelection, final boolean pFocus) {
			assert pListe != null;

			final Component res;
			if (pObjet instanceof PlayerType) {
				final PlayerType pt = (PlayerType) pObjet;
				final JLabel lab = (JLabel) super.getListCellRendererComponent(
						pListe, pt.getName(), pIndex, pSelection, pFocus);
				if (pt.isHuman()) {
					lab.setIcon(HUMAN_ICON);
				} else {
					lab.setIcon(COMPUTER_ICON);
				}
				res = lab;
			} else {
				assert false;
				res = super.getListCellRendererComponent(pListe, pObjet,
						pIndex, pSelection, pFocus);
			}

			return res;
		}
	}
}
